package ru.compscicenter.uno.wizard;

import ru.compscicenter.uno.GameSettings;
import ru.compscicenter.uno.actor.bot.Bot;
import ru.compscicenter.uno.actor.human.Human;
import ru.compscicenter.uno.controller.ClientController;
import ru.compscicenter.uno.controller.ServerController;
import ru.compscicenter.uno.log.Logger;
import ru.compscicenter.uno.model.StringRepresentation;
import ru.compscicenter.uno.net.TCPClient;
import ru.compscicenter.uno.net.TCPServer;
import ru.compscicenter.uno.net.UDPClient;
import ru.compscicenter.uno.view.ConsoleViewer;
import ru.compscicenter.uno.view.SwingViewer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.TreeSet;

/**
 * User: SLeeP
 * Date: 11.04.12
 * Time: 3:10
 */
public class WizardConsole {
    private GameSettings gameSettings;
    private BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    public WizardConsole() {
        gameSettings = new GameSettings();
    }

    public void start() {
        System.out.println("Write your name:");
        try {
            gameSettings.name = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

        

        System.out.println("Server or client?");
        try {
            gameSettings.mode = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

        if (gameSettings.mode.equalsIgnoreCase("server")) {
            String addr = null;
            while (addr == null) {
                addr = getNetworkInterface();
            }

            gameSettings.networkInterface = addr;
            gameSettings.serverController = new ServerController(true, gameSettings.name);
            gameSettings.serverController.startGameBroadcast(addr);
            try {
                while (!br.readLine().equals("start")) {
                    gameSettings.serverController.startGameBroadcast(addr);
                    Thread.sleep(2000);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            gameSettings.serverController.initPlayers();
            gameSettings.serverController.startRound();
            gameSettings.view = new ConsoleViewer(gameSettings.serverController, new Human());
            gameSettings.view.run();
        } else {
            String addr = null;
            gameSettings.clientController = new ClientController(true, false);
            boolean isConnected = false;
            while (!isConnected) {
                while (addr == null) {
                    addr = chooseServer();
                }
                gameSettings.address = addr;
                try {
                    gameSettings.clientController.connect(gameSettings.address, gameSettings.name);
                    String respond = gameSettings.clientController.getRespond();
                    if (respond.startsWith("Connected")) {
                        isConnected = true;
                        String[] spl = respond.split(":");
                        gameSettings.clientController.runTCPClient();
                    }
                } catch (IOException e) {
                    System.out.println("Failed to connect to the selected server!!! Try another one!!!");
                    Logger.write("Failed to connect to the selected server: " + e.toString(), Logger.Mode.ERROR);
                }
            }
            while (!gameSettings.clientController.isReady) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                }
            }
            gameSettings.view = new ConsoleViewer(gameSettings.clientController, new Human());
            gameSettings.view.run();
        }
    }


    
    public void startServer(String name, int n) {
        GameSettings gameSettings = new GameSettings();
        gameSettings.name = name;
        gameSettings.serverController = new ServerController(true, gameSettings.name);
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        gameSettings.clientController = new ClientController(false, true);
        try {
            gameSettings.clientController.connect(gameSettings.address + ":3129", gameSettings.name);
            String respond = gameSettings.clientController.getRespond();
            if (respond.startsWith("Connected")) {
                String[] spl = respond.split(":");
                gameSettings.clientController.runTCPClient();
            }
        } catch (IOException e) {
            System.out.println("Failed to connect to the selected server!!! Try another one!!!");
            Logger.write("Failed to connect to the selected server: " + e.toString(), Logger.Mode.ERROR);
        }

        gameSettings.serverController.initPlayers();
        gameSettings.serverController.startRound();

        while (!gameSettings.clientController.isReady) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Logger.write("Interrupted while waiting settings: " + e.toString(), Logger.Mode.ERROR);
            }
        }
        gameSettings.view = new ConsoleViewer(gameSettings.clientController, new Bot(gameSettings.clientController));
        gameSettings.view.run();
    }
    
    public void startClient(String name, String ip) {
        GameSettings gameSettings = new GameSettings();
        gameSettings.name = name;
        gameSettings.address = ip;
        gameSettings.clientController = new ClientController(false, false);
        try {
            gameSettings.clientController.connect(gameSettings.address, gameSettings.name);
            String respond = gameSettings.clientController.getRespond();
            if (respond.startsWith("Connected")) {
                String[] spl = respond.split(":");
                gameSettings.clientController.runTCPClient();
            }
        } catch (IOException e) {
            System.out.println("Failed to connect to the selected server!!! Try another one!!!");
            Logger.write("Failed to connect to the selected server: " + e.toString(), Logger.Mode.ERROR);
        }

        while (!gameSettings.clientController.isReady) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Logger.write("Interrupted while waiting settings: " + e.toString(), Logger.Mode.ERROR);
            }
        }
        gameSettings.view = new ConsoleViewer(gameSettings.clientController, new Bot(gameSettings.clientController));
        gameSettings.view.run();
    }
    
    private String getNetworkInterface() {
        System.out.println("Choose your network interface:");
        ArrayList<String> networkInterfaces = TCPServer.getNetworkInterface();
        int i = 1;

        for (String addr : networkInterfaces) {
            System.out.println(i++ + ". " + addr);
        }

        try {
            int num = Integer.parseInt(br.readLine());
            return networkInterfaces.get(num - 1);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IndexOutOfBoundsException e) {
            System.out.println("Wrong index");
        } catch (NumberFormatException e) {
            System.out.println("Wrong index");
        }

        return null;
    }

    private String chooseServer() {
        System.out.println("Choose server ot type another IP:");

        UDPClient udpClient = null;
        try {
            udpClient = new UDPClient();
            Object[] availableServers = udpClient.findServers().toArray();
            System.out.println("Choose server or type another IP:");

            for (int i = 0; i != availableServers.length; i++) {
                System.out.println(availableServers[i]);
            }

            String ip = br.readLine();
            if (checkIP(ip)) {
                return ip;
            } else {
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

        return null;
    }

    private boolean checkIP(String ipAddress) {
        try {
            if (ipAddress.matches("[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\:[0-9]{1,6}")) {
                String[] parts = ipAddress.split("\\:");
                String[] ip = parts[0].split("\\.");
                String port = parts[1];

                for (String s : ip) {
                    int i = Integer.parseInt(s);
                    if (i < 0 || i > 255) {
                        return false;
                    }
                }
                return true;
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }
}
